package cn.itcast.ssh.config;

import java.util.Properties;

import javax.sql.DataSource;

import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.orm.hibernate5.HibernateTemplate;
import org.springframework.orm.hibernate5.HibernateTransactionManager;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import com.mchange.v2.c3p0.ComboPooledDataSource;

/**
 * Spring注解配置类
 * 
 * @author Shugui
 *
 */
@Configuration // 声明该类是一个Spring配置类
@ComponentScan(basePackages = { "cn.itcast.ssh" }) // 扫描包并进行自动装配Bean
@PropertySource("classpath:application.properties") // 加载Properties配置文件
@EnableTransactionManagement // 开启注解型事务配置
public class ApplicationConfig {
	/**
	 * 数据库驱动
	 */
	@Value("${jdbc.driver}")
	private String driver;
	/**
	 * 数据库连接地址
	 */
	@Value("${jdbc.url}")
	private String url;
	/**
	 * 数据库用户名
	 */
	@Value("${jdbc.user}")
	private String user;
	/**
	 * 数据库密码
	 */
	@Value("${jdbc.password}")
	private String password;
	/**
	 * hibernate映射转DDL语句策略
	 */
	@Value("${hibernate.hbm2ddl.auto}")
	private String hbm2ddlAuto;
	/**
	 * hibernate数据库方言
	 */
	@Value("${hibernate.dialect}")
	private String dialect;
	/**
	 * 是否显示SQL语句
	 */
	@Value("${hibernate.show_sql}")
	private String showSql;
	/**
	 * 是否格式化SQL语句
	 */
	@Value("${hibernate.format_sql}")
	private String formatSql;
	/**
	 * Hibernate的session绑定线程策略
	 */
	@Value("${hibernate.current_session_context_class}")
	private String currentSessionContextClass;
	/**
	 * 解决hibernate检索数据库元数据时抛出的异常
	 */
	@Value("${hibernate.temp.use_jdbc_metadata_defaults}")
	private String tempUseJdbcMetadataDefaults;

	/**
	 * 在Spring4.3版本之前想要Spring全注解的方式来使用@PropertySource注解解析Properties文件,必须配置这个Bean
	 * 
	 * @return Properties配置文件解析器
	 */
	@Bean
	public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
		PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer();
		return propertySourcesPlaceholderConfigurer;
	}

	/**
	 * 配置C3P0数据源
	 * 
	 * @return 数据源
	 * @throws Exception
	 */
	@Bean(name = "dataSource")
	public DataSource dataSource() throws Exception {
		ComboPooledDataSource dataSource = new ComboPooledDataSource();
		dataSource.setDriverClass(driver);
		dataSource.setJdbcUrl(url);
		dataSource.setUser(user);
		dataSource.setPassword(password);
		return dataSource;
	}

	/**
	 * 配置Hibernate的SessionFactory工厂
	 * 
	 * @param dataSource
	 *            数据源
	 * @return SessionFactory
	 * @throws Exception
	 */
	@Bean(name = "sessionFactory")
	public SessionFactory sessionFactory(@Qualifier("dataSource") DataSource dataSource) throws Exception {
		LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
		sessionFactoryBean.setDataSource(dataSource);
		Properties properties = new Properties();
		properties.setProperty("hibernate.hbm2ddl.auto", hbm2ddlAuto);
		properties.setProperty("hibernate.dialect", dialect);
		properties.setProperty("hibernate.show_sql", showSql);
		properties.setProperty("hibernate.format_sql", formatSql);
		properties.setProperty("hibernate.current_session_context_class", currentSessionContextClass);
		properties.setProperty("hibernate.temp.use_jdbc_metadata_defaults", tempUseJdbcMetadataDefaults);
		sessionFactoryBean.setHibernateProperties(properties);
		sessionFactoryBean.setPackagesToScan("cn.itcast.ssh.entity");
		sessionFactoryBean.afterPropertiesSet();
		SessionFactory sessionFactory = sessionFactoryBean.getObject();
		return sessionFactory;
	}

	/**
	 * 配置Spring提供的操作Hibernate框架的模板类
	 * 
	 * @param sessionFactory
	 *            Hibernate的SessionFactory工厂
	 * @return hibernateTemplate
	 */
	@Bean(name = "hibernateTemplate")
	public HibernateTemplate hibernateTemplate(@Qualifier("sessionFactory") SessionFactory sessionFactory) {
		HibernateTemplate hibernateTemplate = new HibernateTemplate(sessionFactory);
		return hibernateTemplate;
	}

	/**
	 * 配置Spring整合Hibernate后提供的事务管理器
	 * 
	 * @param sessionFactory
	 *            Hibernate的SessionFactory工厂
	 * @return transactionManager
	 */
	@Bean(name = "transactionManager")
	public PlatformTransactionManager transactionManager(@Qualifier("sessionFactory") SessionFactory sessionFactory) {
		HibernateTransactionManager transactionManager = new HibernateTransactionManager(sessionFactory);
		return transactionManager;
	}
}
